<script setup lang="ts">
import type { Action } from 'element-plus';

import type { Ref } from 'vue';

import type { GDVSceneConfig, GroupLayer, Layer, Scene } from '../index';

import {
  markRaw,
  nextTick,
  onMounted,
  provide,
  reactive,
  ref,
  watch,
} from 'vue';
import { onBeforeRouteLeave, useRouter } from 'vue-router';

import { useAppConfig } from '@vben/hooks';
import {
  BiGlobe,
  BxExport,
  BxLayer,
  BxsLayer,
  ElCirclePlus,
  ElClose,
  ElDArrowLeft,
  ElDArrowRight,
  ElFolderChecked,
  ElFullScreen,
  ElHomeFilled,
  ElMapLocation,
  ElQuestionFilled,
  ElTools,
  MingcuteSave2Line,
  PixelarticonsGrid,
  SimpleLineIconsQuestion,
  SvgMapIcon,
  SystemUiconsWrapBack,
} from '@vben/icons';
import { cloneDeep } from '@vben/utils';

import { StorageManager } from '@vben-core/shared/cache';

// @ts-ignore
import MapboxDraw from '@mapbox/mapbox-gl-draw';
import * as turf from '@turf/turf';
import {
  ElButton,
  ElCol,
  ElDialog,
  ElDivider,
  ElIcon,
  ElInput,
  ElLoading,
  ElMenu,
  ElMenuItem,
  ElMessage,
  ElMessageBox,
  ElPopover,
  ElRow,
  ElSpace,
  ElTag,
  ElTooltip,
} from 'element-plus';
import mapboxGl from 'mapbox-gl';
import { nanoid } from 'nanoid';

import { historyApi, rasterServiceApi, sceneApi } from '#/api';
import {
  AnimationControl,
  BaseMapControl,
  GDVSceneSettingPanel,
  Jump2EraControl,
  LayerPanel,
  LayerProperty,
  TimeRulerControl,
  YearSelection,
} from '#/components/scene-editor';
import { useMapStore, usePublicStore, useSceneStore } from '#/store';
import {
  addCompositeLayer,
  baseMapLayers,
  cryptoUtil,
  dataURLtoFile,
  getLastLayerOfTree,
  getRasterLayerConfig,
  getTextLabelParams,
  getVectorLayerConfig,
  html2canvasTool,
  isSourceUsedByLayer,
  layerRenderUtil,
  normalizeConfig,
  removeCompositeLayer,
  returnViewLayerPaintConfig,
  switchBaseMap,
} from '#/utils';

import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
// import { duration } from "html2canvas/dist/types/css/property-descriptors/duration";
const { initRender, renderEntry, handleSetLayerVisibility, loadLayersToMap } =
  layerRenderUtil();

const storageManager = new StorageManager({
  prefix: '',
  storageType: 'sessionStorage',
});
interface animationOption {
  title: string;
  groupLayerId: string;
  timeInterval: number;
  loop: boolean;
  fitExtent: boolean;
  layerList: Array<any>;
}

const { mapboxAssetsIP } = useAppConfig(import.meta.env, import.meta.env.PROD);
const publicStore = usePublicStore();
const isAnimationControlShow = ref(false);
mapboxGl.accessToken =
  'pk.eyJ1IjoibmluamFhIiwiYSI6ImNsYXYzd3JwaDAyMGwzdm44ZmI3M212eHQifQ.h_dGMMOvQXNfmheNd0_j8A';
const sceneStore = useSceneStore();
const mapStore = useMapStore();
const mapbox = reactive({
  map: null as any,
});
const router = useRouter();
const mapContainer: Ref<HTMLElement | undefined> = ref();
const layerPannelRef = ref();
const isCollapse = ref(true);
const isLayerPropertyDialogShow = ref(false);
const currentSelectedLayer = ref(null as any);
const sceneLayersGroup = ref([] as any);
const sceneSourcesGroup = ref([] as any);
const activatedMenu = ref('0');
const loadingText = ref('场景加载中...');
const zoomText = ref();
const showCenter = ref('');
const saveSceneDialog = ref(false);
const isReadonly = ref(true);
const isSceneRenaming = ref(false);
const isExportDialogVisible = ref(false);
const mapMode = ref('mercator');
const mapModeList = ref([
  {
    id: 1,
    name: '平面',
    value: 'mercator',
  },
  {
    id: 2,
    name: '3D',
    value: 'globe',
  },
]);

const animationParams = ref({} as animationOption);
const showTimeRuler = ref(false);
const showJump2Era = ref(false);
const isHistoryMode = ref(false);
provide('layerList', sceneLayersGroup);
provide('currentSelectedLayer', currentSelectedLayer);
let draw: MapboxDraw;
// 初始化空地图
const initMap = () => {
  return new Promise((resolve) => {
    mapbox.map = new mapboxGl.Map({
      container: 'map-container', // container ID
      style: {
        version: 8,
        sources: {
          localTiles: {
            type: 'raster',
            tiles: [
              'http://32.12.195.125/basemap-server/tile?x={x}&y={y}&z={z}',
            ], // 本地瓦片服务 URL
            tileSize: 256,
            minzoom: 0,
            maxzoom: 9,
          },
        },
        // glyphs: "mapbox://fonts/mapbox/{fontstack}/{range}.pbf",
        glyphs: `${mapboxAssetsIP}/glyphs/fonts/{fontstack}/{range}.pbf`,
        sprite: `${mapboxAssetsIP}/sprites/` + `mapstudio` + `/sprite`,
        layers: [
          {
            id: 'localTilesLayer',
            type: 'raster',
            source: 'localTiles',
            minzoom: 0,
            maxzoom: 9,
          },
        ],
      },
      // style: 'mapbox://styles/mapbox/streets-v11',
      center: [118.9, 32.08], // starting position [lng, lat]
      zoom: 3, // starting zoom
      // projection: "globe",
      preserveDrawingBuffer: true,
      attributionControl: false,
    });

    // 有mapbox自带的地图底图的情况下才需要该汉化
    // mapbox.map.addControl(new MapboxLanguage({
    //   defaultLanguage: 'zh-Hans'
    // }));
    resolve('地图初始化成功！正在加载场景配置项...');
    draw = new MapboxDraw({
      displayControlsDefault: true,
    });
    mapbox.map.addControl(
      new mapboxGl.NavigationControl({
        visualizePitch: true,
      }),
    );
    mapbox.map.addControl(draw);
    // 存储 featureId 对应的 Marker 实例
    const drawMarkers = new Map<string, mapboxgl.Marker>();
    let lastFeatureId: null | string = null;
    mapbox.map.on('draw.modechange', (e: any) => {
      const mode = e.mode;
      if (
        (mode === 'draw_polygon' || mode === 'draw_line_string') &&
        lastFeatureId
      ) {
        draw.delete(lastFeatureId);
        const oldMarker = drawMarkers.get(lastFeatureId);
        if (oldMarker) {
          oldMarker.remove();
          drawMarkers.delete(lastFeatureId);
        }
        lastFeatureId = null;
      }
    });
    mapbox.map.on('draw.create', (e: any) => {
      const feature = e.features[0];
      const featureId = feature.id;

      lastFeatureId = featureId;

      let markerText = '';
      let markerCoord: [number, number] = [0, 0];

      if (feature.geometry.type === 'Polygon') {
        const area = turf.area(feature);
        markerText = `${(area / 1_000_000).toFixed(2)} km²`;
        const centroid = turf.centroid(feature);
        markerCoord = centroid.geometry.coordinates as [number, number];
      }

      if (feature.geometry.type === 'LineString') {
        const line = turf.lineString(feature.geometry.coordinates);
        const length = turf.length(line, { units: 'kilometers' });
        markerText = `${length.toFixed(2)} km`;
        const midpointIndex = Math.floor(
          feature.geometry.coordinates.length / 2,
        );
        markerCoord = feature.geometry.coordinates[midpointIndex];
      }

      const markerEl = document.createElement('div');
      markerEl.className = 'draw-result-marker';
      markerEl.style.cssText = `
    padding: 6px 12px;
    background: rgba(255, 255, 255, 0.95);
    border-radius: 12px;
    font-size: 12px;
    font-weight: 500;
    color: #333;
    backdrop-filter: blur(8px);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
    border: 1px solid rgba(0, 0, 0, 0.08);
    transition: all 0.2s ease-in-out;
  `;

      markerEl.innerText = markerText;

      const marker = new mapboxGl.Marker(markerEl)
        .setLngLat(markerCoord)
        .addTo(mapbox.map);

      // 存储 marker
      drawMarkers.set(featureId, marker);
    });
    mapbox.map.on('draw.delete', (e: any) => {
      e.features.forEach((feature: any) => {
        const featureId = feature.id;
        const marker = drawMarkers.get(featureId);
        if (marker) {
          marker.remove();
          drawMarkers.delete(featureId);
        }
      });
    });

    // 添加比例尺
    const scale = new mapboxGl.ScaleControl({
      maxWidth: 120,
    });
    mapbox.map.addControl(scale);
    scale.setUnit('metric');
    // 添加定位控件
    mapbox.map.addControl(
      new mapboxGl.GeolocateControl({
        positionOptions: {
          enableHighAccuracy: true,
        },
        trackUserLocation: true,
      }),
    );
    // mapbox.map.on("load", () => {
    //   console.log("地图初始化成功！正在加载场景配置项...");
    //   resolve("地图初始化成功！正在加载场景配置项...");

    //   //时序test
    //   // mapbox.map.addSource('radar', {
    //   //   type: 'image',
    //   //   url: getPath(),
    //   //   coordinates: [
    //   //     [-80.425, 46.437],
    //   //     [-71.516, 46.437],
    //   //     [-71.516, 37.936],
    //   //     [-80.425, 37.936]
    //   //   ]
    //   // });
    //   // mapbox.map.addLayer({
    //   //   id: 'radar-layer',
    //   //   'type': 'raster',
    //   //   'source': 'radar',
    //   //   'paint': {
    //   //     'raster-fade-duration': 0
    //   //   }
    //   // });
    // });
    mapbox.map.on('zoom', () => {
      zoomText.value = mapbox.map.getZoom().toFixed(2);
    });
    mapbox.map.on('mousemove', (e: any) => {
      showCenter.value = `(${String(e.lngLat.lng.toFixed(5))}，${String(
        e.lngLat.lat.toFixed(5),
      )})`;
    });
  });
};
const handleZoomToLayer = (layer: any) => {
  // 需要获取图层bbox或中心点
  // if (layer.type === 'raster') {
  //   ElMessage.error('该图层暂不支持缩放!')
  //   return
  // }
  const sourceId = mapbox.map.getSource(layer.source).id;
  const source = sceneSourcesGroup.value.find(
    (item: any) => item.sourceId === sourceId,
  );
  if (source) {
    if (source.bbox) {
      mapbox.map.fitBounds(source.bbox, {
        pitch: sceneStore.currentSceneConfig.pos.pitch,
        bearing: sceneStore.currentSceneConfig.pos.bearing,
        padding: { top: 50, bottom: 50, left: 50, right: 50 },
        // linear: true,
        duration: 0,
      });
    } else {
      ElMessage.error('该图层暂不支持缩放!');
    }
  } else {
    // ElMessage.error('当前图层对应的数据源不存在，请检查！')
    ElMessage.error('该图层暂不支持缩放!');
  }
};
// const currentImage = 0;

// const changeFrame = (currentImageCount: number) => {
//   currentImage = currentImageCount;
//   mapbox.map.getSource('radar').updateImage({ url: getPath() });
// }
const changeFrame = (
  currentLayerId: string,
  groupLayerId: string,
  fitExtent: boolean,
) => {
  const groupLayer = sceneStore.currentSceneConfig.layers.find(
    (item: any) => item.id === groupLayerId,
  ) as GroupLayer;
  const currentLayer = groupLayer?.layers?.find(
    (item: any) => item.id === currentLayerId,
  );
  if (fitExtent) handleZoomToLayer(currentLayer);
  let keys = layerPannelRef.value.getCheckedKeys();
  // 如果组勾选（全选），先取消全选
  if (keys.includes(groupLayerId)) {
    keys = keys.filter((item: any) => item !== groupLayerId);
  }
  // 否则取消勾选组内除当前图层以外的其他图层
  keys = keys.filter(
    (item: any) =>
      !groupLayer?.layers?.map((layer: any) => layer.id).includes(item),
  );
  layerPannelRef.value.setCheckedKeys(keys);
  // 勾选当前图层
  keys.push(currentLayerId);
  layerPannelRef.value.setCheckedKeys(keys);
};
const handleSwitchMap = ({ id, type, label }: any) => {
  const lastLayerId = mapbox.map.getStyle().layers[0]
    ? mapbox.map.getStyle().layers[0].id
    : '';

  const groupId = `group_${id}`;
  let lastGroupId = '';
  if (sceneStore.currentSceneConfig.layers.length > 0) {
    lastGroupId =
      sceneStore.currentSceneConfig.layers[
        sceneStore.currentSceneConfig.layers.length - 1
      ]?.id || '';
  }
  // 同类型不切换
  if (lastGroupId === groupId) return;

  // 存在底图的情况下，删除图层列表对应项
  const isBaseMapExist = sceneStore.currentSceneConfig.layers.some(
    (layer: any) =>
      ['group_img_map', 'group_ter_map', 'group_vec_map'].includes(layer.id),
  );
  if (isBaseMapExist) {
    sceneStore.currentSceneConfig.layers.pop();
  }

  switchBaseMap(mapbox.map, type, lastLayerId);
  // ElMessage.success(`已切换至${label}底图`);

  // 更新图层列表
  if (type === 'blank') return;
  const baseMapGroup = {
    id: groupId,
    name: `${label}底图`,
    layers: [] as any,
    organizationType: 'groupLayer',
  };
  switch (type) {
    case 'image': {
      baseMapGroup.layers = baseMapLayers.image[1]
        ? [baseMapLayers.image[1], baseMapLayers.image[0]]
        : [baseMapLayers.image[0]];
      break;
    }
    case 'terrain': {
      baseMapGroup.layers = [
        baseMapLayers.terrain[1],
        baseMapLayers.terrain[0],
      ];

      break;
    }
    case 'vector': {
      baseMapGroup.layers = [baseMapLayers.vector[1], baseMapLayers.vector[0]];

      break;
    }
    // No default
  }
  sceneStore.currentSceneConfig.layers.push(baseMapGroup as GroupLayer);
};

const toggleMapMode = (mode: any, init: boolean = false) => {
  const { value, name } = mode;
  if (value === mapMode.value) return;
  mapMode.value = value;
  mapbox.map.setProjection(value);
  if (value === 'globe') {
    mapbox.map.setFog({});
  } else {
    mapbox.map.setFog(null);
  }
  if (!init) {
    // update store
    sceneStore.currentSceneConfig.mapParams.mapMode =
      value === 'mercator' ? 0 : 1;
    ElMessage.success(`已切换至${name}模式`);
  }
};

const handleSelect = (key: string) => {
  activatedMenu.value = key;
};

const getDefaultConfig = (): GDVSceneConfig => {
  return {
    sceneId: '',
    // userId: localStorage.getItem('userId'),
    // thumbnail: '',
    sources: [],
    layers: [],
    pos: {
      bearing: 0,
      pitch: 0,
    },
    mapParams: {
      center: [118.9, 32.08],
      zoom: 11,
      mapMode: 0, // 0:'mercator',1:'globe'
      historyMap: null,
    },
    sprite: 'mapstudio',
  };
};

const getSceneConfig = async () => {
  const config = await sceneApi.getGDVSceneConfig(
    sceneStore.editingScene.sceneId,
  );
  delete config.id;
  sceneStore.setCurrentSceneConfig(normalizeConfig(config));
  sceneLayersGroup.value = sceneStore.currentSceneConfig.layers;
  sceneSourcesGroup.value = sceneStore.currentSceneConfig.sources;
  return '地图场景配置项加载完毕！正在渲染数据...';
};
const requestMapConfig = () => {
  // 如果是新建空场景，手动初始化一个空配置
  return sceneStore.editingScene.sceneId === ''
    ? new Promise<string>((resolve) => {
        sceneStore.setCurrentSceneConfig(getDefaultConfig());
        resolve('地图场景配置项加载完毕！');
      })
    : getSceneConfig();
};

const initMapMode = () => {
  const mode = sceneStore.currentSceneConfig.mapParams.mapMode
    ? {
        id: 2,
        name: '3D',
        value: 'globe',
      }
    : {
        id: 1,
        name: '平面',
        value: 'mercator',
      };
  toggleMapMode(mode, true);
};

const initMapState = (duration = 1500) => {
  mapbox.map.easeTo({
    center: sceneStore.currentSceneConfig.mapParams.center, // 目标中心点坐标
    zoom: sceneStore.currentSceneConfig.mapParams.zoom, // 目标缩放级别
    bearing: sceneStore.currentSceneConfig.pos.bearing, // 目标旋转角度（以度为单位，可选）
    pitch: sceneStore.currentSceneConfig.pos.pitch, // 目标俯仰角（以度为单位，可选）
    duration, // 动画持续时间（以毫秒为单位，可选）
  });
};
const exportGeojson = () => {
  // console.log('当前 draw:', draw);

  if (!mapbox.map || !draw) {
    console.warn('Map 或 Draw 实例未初始化');
    return;
  }

  const data = draw.getAll();
  console.warn('当前绘图数据：', data);
};

const renderSceneLayersInMap = () => {
  return new Promise((resolve) => {
    loadLayersToMap().then(() => {
      initMapState();
      // flyToDataBounds()
    });
    mapbox.map.on('moveend', function onMoveEnd() {
      resolve('图层渲染完毕！');
      mapbox.map.off('moveend', onMoveEnd);
    });
  });
};
const getImageCoordinates = (source: any) => {
  return [
    [source.bbox[0], source.bbox[3]],
    [source.bbox[2], source.bbox[3]],
    [source.bbox[2], source.bbox[1]],
    [source.bbox[0], source.bbox[1]],
  ];
};
const getMapSource = (source: any) => {
  let dataSource;
  switch (source.sourceType) {
    case 'geojson': {
      dataSource = {
        type: 'geojson',
        data: source.url,
      };
      break;
    }
    case 'image': {
      dataSource = {
        type: source.sourceType,
        url: `${source.url}?version=${Date.now()}`,
        coordinates: getImageCoordinates(source),
      };
      break;
    }
    case 'tiles': {
      dataSource = {
        type: 'raster',
        tiles: [source.url],
        tileSize: 256,
      };
      break;
    }
    case 'vector': {
      dataSource = {
        type: source.sourceType,
        tiles: [source.url],
      };
      break;
    }
    default: {
      break;
    }
  }
  return dataSource;
};
const loadSourcesToMap = () => {
  return new Promise((resolve) => {
    for (let i = sceneSourcesGroup.value.length - 1; i >= 0; i--) {
      // 如果源有聚合属性
      const dataSource = sceneSourcesGroup.value[i].clusterOptions
        ? {
            type: 'geojson',
            data: sceneSourcesGroup.value[i].url,
            cluster: true,
            clusterMaxZoom:
              sceneSourcesGroup.value[i].clusterOptions.clusterMaxZoom,
            clusterRadius:
              sceneSourcesGroup.value[i].clusterOptions.clusterRadius,
          }
        : getMapSource(sceneSourcesGroup.value[i]);
      mapbox.map.addSource(sceneSourcesGroup.value[i].sourceId, dataSource);
    }
    resolve('加载数据源完毕');
  });
};

const addNewSource = async (source: any) => {
  // 添加副本
  if (source.sourceType === 'image' && source.fileType === 'tif') {
    const param = {
      userId: storageManager.getItem<string>('userId') as string,
      sceneId: sceneStore.editingScene.sceneId,
      rasterSId: source.sourceId,
    };
    source.url = await rasterServiceApi.addRasterSCopy(param);
  }
  sceneStore.currentSceneConfig.sources.unshift(source);
  mapbox.map.addSource(source.sourceId, getMapSource(source));
  // console.log('添加的数据源', dataSource);
};

const backScene = () => {
  router.back();
};

const beforeSceneSave = async () => {
  const bearing = mapbox.map.getBearing();
  const pitch = mapbox.map.getPitch();
  const zoom = mapbox.map.getZoom();
  const { lng, lat } = mapbox.map.getCenter();
  let sceneImgCanvas: HTMLCanvasElement;
  if (mapContainer.value) {
    sceneImgCanvas = await html2canvasTool(mapContainer.value);
  } else {
    ElMessage.warning('场景图片生成失败，请刷新页面重试');
    return false;
  }
  const sceneImg = sceneImgCanvas.toDataURL();
  // const sceneImg = mapbox.map.getCanvas().toDataURL();
  sceneStore.currentSceneConfig.pos.bearing = bearing;
  sceneStore.currentSceneConfig.pos.pitch = pitch;
  sceneStore.currentSceneConfig.mapParams.zoom = zoom;
  sceneStore.currentSceneConfig.mapParams.center = [lng, lat];
  sceneStore.editingScene.sceneImg = sceneImg.replace(
    'data:image/png;base64,',
    '',
  );
  const sceneImgFile = dataURLtoFile(sceneImg, cryptoUtil.Encrypt(Date.now()));
  const saveSceneData = new FormData();
  saveSceneData.append('sceneId', sceneStore.editingScene.sceneId);
  saveSceneData.append('userId', sceneStore.editingScene.userId);
  saveSceneData.append('name', sceneStore.editingScene.sceneName);
  saveSceneData.append('thumbnail', sceneImgFile);
  saveSceneData.append(
    'sources',
    JSON.stringify(sceneStore.currentSceneConfig.sources),
  );
  // 深拷贝，防止影响原数组
  const saveLayerData = cloneDeep(sceneStore.currentSceneConfig.layers);
  const updatedSaveLayerData = saveLayerData.map((layer: any) => {
    return layer.organizationType === 'singleLayer'
      ? returnViewLayerPaintConfig(layer)
      : {
          ...layer,
          layers: layer.layers.map((subLayer: any) =>
            returnViewLayerPaintConfig(subLayer),
          ),
        };
  });

  saveSceneData.append('layers', JSON.stringify(updatedSaveLayerData));
  saveSceneData.append(
    'pos',
    JSON.stringify(sceneStore.currentSceneConfig.pos),
  );
  saveSceneData.append(
    'mapParams',
    JSON.stringify(sceneStore.currentSceneConfig.mapParams),
  );
  saveSceneData.append('sprite', sceneStore.currentSceneConfig.sprite);
  // console.log('保存后场景配置', sceneStore.currentSceneConfig);
  try {
    const {
      id,
      name,
      type,
      thumbnail,
      createdUser,
      editCount,
      createdTime,
      updatedTime,
      isLocked,
      permissionRange,
    } = await sceneApi.saveScene(saveSceneData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
    });
    const editingScene = {
      sceneId: id,
      sceneName: name,
      sceneType: type,
      sceneImg: `${thumbnail}?version=${Date.now()}`,
      userId: createdUser,
      editCount,
      createdTime,
      lastUpdatedTime: updatedTime,
      isLocked,
      permissionRange,
    };
    // 更新session和store
    storageManager.setItem('editingScene', editingScene);
    sceneStore.setEditingScene(editingScene);
    return '保存场景成功！';
  } catch {
    return false;
  }
};
const handleSaveConfrim = async (delay: number = 0) => {
  // saveSceneDialog.value = false
  const sceneLoading = ElLoading.service({
    lock: true,
    text: loadingText.value,
    background: 'rgba(0, 0, 0, 0.7)',
  });
  sceneLoading.setText('正在保存场景配置项...');
  // 提供延时保存，防止渲染结束立即保存截图时仍然截的是渲染之前的样式（tif)
  await new Promise((resolve) => setTimeout(resolve, delay));
  const saveResult = await beforeSceneSave();
  sceneLoading.close();
  if (saveResult) {
    sceneLoading.setText(saveResult as string);
    ElMessage.success('场景保存成功');
  }
};

const handleCloseLayerPannel = () => {
  activatedMenu.value = '0';
};

const formatDateTime = () => {
  const date = new Date();
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');
  const seconds = String(date.getSeconds()).padStart(2, '0');
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};

// 导出表单数据
const exportForm = reactive({
  mapName: '',
  introduction: '',
});

// 表单验证规则
const exportRules = {
  mapName: [
    { required: true, message: '请输入地图名称', trigger: 'blur' },
    { max: 20, message: '名称不能超过20个字符', trigger: 'blur' },
  ],
  introduction: [
    { max: 200, message: '介绍不能超过200个字符', trigger: 'blur' },
  ],
};
// 表单引用
const exportFormRef = ref(null);

// 点击“导出”按钮时，显示弹窗
const handleExport = () => {
  exportForm.mapName = sceneStore.editingScene.sceneName || '';
  exportForm.introduction = '';
  isExportDialogVisible.value = true;
};

// 导出场景地图
const confirmExport = async () => {
  // 表单验证
  // const valid = await exportFormRef.value.validate();
  // if (!valid) return; // 验证失败则不继续

  const mapStyle = mapbox.map.getStyle();
  const sceneId = sceneStore.editingScene.sceneId;
  const userId = sceneStore.editingScene.userId;
  // 对话框获取mapName, introduction
  const mapName = exportForm.mapName;
  const introduction = exportForm.introduction;

  const mapResponse = await sceneApi.publishMap(
    sceneId,
    userId,
    mapName,
    mapStyle,
    introduction,
  );
  console.log('发布地图返回值', mapResponse);
  const { mapId, mapUrl } = mapResponse;
  const publishMap = {
    mapId,
    mapStyle,
    mapUrl,
    mapName,
    userId,
    publishTime: formatDateTime(),
    introduction,
  };
  mapStore.setPublishMap(publishMap);

  if (mapUrl !== '' && mapUrl !== null) {
    const action = await ElMessageBox.confirm('场景地图导出成功', {
      distinguishCancelAndClose: true,
      confirmButtonText: '预览',
      cancelButtonText: '退出',
      type: 'info',
    });
    if (action === 'confirm') {
      router.push(`/map-preview/${mapId}`);
    }
  } else {
    ElMessage.warning('场景地图导出失败');
  }
  activatedMenu.value = '0';
};

// 弹窗关闭时重置表单
// const resetForm = () => {
//   exportFormRef.value.resetFields();
// };

const handletoggleFullScreen = () => {
  const mapContainer = mapbox.map.getContainer();

  //  兼容不同浏览器
  const rfs =
    mapContainer.requestFullscreen ||
    mapContainer.webkitRequestFullScreen ||
    mapContainer.mozRequestFullScreen ||
    mapContainer.msRequestFullscreen;

  if (rfs) {
    rfs.call(mapContainer);
  }
};
const handletoggleCloseHistoryMap = () => {
  const map = mapbox.map;

  // 1. 状态关闭
  isHistoryMode.value = false;
  showTimeRuler.value = false;
  showJump2Era.value = false;
  sceneStore.currentSceneConfig.mapParams.historyMap = 0;

  // 2. 移除历史底图的图层（source === 'dlsgis_his_regime'）
  const style = map.getStyle();
  const historyLayerIds = (style.layers || [])
    .filter((layer: { source: string }) => layer.source === 'dlsgis_his_regime')
    .map((layer: { id: any }) => layer.id);

  for (const layerId of historyLayerIds) {
    if (map.getLayer(layerId)) {
      map.removeLayer(layerId);
    }
  }

  // 3. 移除历史底图的 source
  if (map.getSource('dlsgis_his_regime')) {
    map.removeSource('dlsgis_his_regime');
  }
};

const loadNewLayerToMap = (layer: any) => {
  return new Promise((resolve) => {
    sceneStore.currentSceneConfig.layers.unshift(layer);
    mapbox.map.addLayer(layer);

    // if (layer.layerConfig.source.type === 'vector') {
    //   Object.assign(layer.layerConfig, {
    //     'source-layer': layer.layerConfig.id
    //   })
    // }
    // mapbox.map.addLayer(layer.layerConfig)
    resolve('图层加载成功！');
  });
};
const handleAddToLayer = async (source: any, layerName: any) => {
  // 如果是矢量源
  const layer = Object.prototype.hasOwnProperty.call(source.value, 'geoType')
    ? getVectorLayerConfig(source.value, layerName)
    : getRasterLayerConfig(source.value, layerName);
  const isExist = sceneStore.currentSceneConfig.sources.find(
    (item: any) => item.sourceId === source.value.sourceId,
  );
  const isTifSource =
    source.value.sourceType === 'image' && source.value.fileType === 'tif';
  if (isExist) {
    // 禁止重复添加tif类图层
    if (isTifSource) {
      ElMessageBox.alert('无法重复添加tif类图层，请先移除后再添加！', '提示', {
        confirmButtonText: '确定',
        type: 'warning',
      });
      return;
    }
  } else {
    const isEmptyS2AddTif =
      isTifSource && sceneStore.editingScene.sceneId === '';
    if (isEmptyS2AddTif) {
      ElMessageBox.alert(
        '无法在临时场景添加tif类图层，请先保存场景后再添加！',
        '提示',
        {
          confirmButtonText: '确定',
          type: 'warning',
        },
      );
      return;
    }
    await addNewSource(source.value);
  }
  loadNewLayerToMap(layer).then((res: any) => {
    if (source.value.bbox) {
      mapbox.map.fitBounds(source.value.bbox, {
        pitch: sceneStore.currentSceneConfig.pos.pitch,
        bearing: sceneStore.currentSceneConfig.pos.bearing,
        padding: { top: 50, bottom: 50, left: 50, right: 50 },
        // linear: true,
        duration: 1300, // 必须有过渡时间，否则moveend不会触发
      });
    }
    ElMessage.success(res);
    mapbox.map.on('moveend', async function onMoveEnd() {
      // 添加图层后保存刚刚添加副本的操作
      if (
        source.value.sourceType === 'image' &&
        source.value.fileType === 'tif'
      ) {
        await handleSaveConfrim();
        mapbox.map.off('moveend', onMoveEnd);
      }
    });
    // handleZoomToLayer(layer)
  });
};
// 补充删除底图源
const removeBaseMapSource = (layer: any) => {
  if (layer.id === 'vec_annotate') {
    mapbox.map.removeSource('vec_mapSource_annotate');
  }
  if (layer.id === 'vec_mapLayer') {
    mapbox.map.removeSource('vec_mapSource_map');
  }
  if (layer.id === 'img_annotate') {
    mapbox.map.removeSource('img_mapSource_annotate');
  }
  if (layer.id === 'img_mapLayer') {
    mapbox.map.removeSource('img_mapSource_map');
  }
};
// 对removeLayer方法的封装
const removeSceneLayer = (compositeLayer: any, type?: any) => {
  removeCompositeLayer(compositeLayer, mapbox.map, type);
};

const removeSource = async (source: any) => {
  mapbox.map.removeSource(source.sourceId);
  sceneStore.currentSceneConfig.sources =
    sceneStore.currentSceneConfig.sources.filter(
      (item: any) => item.sourceId !== source.sourceId,
    );
  // 摘除副本并保存
  if (source.sourceType === 'image' && source.fileType === 'tif') {
    await rasterServiceApi.deleteRasterSCopy(
      sceneStore.editingScene.sceneId,
      source.sourceId,
    );
    await handleSaveConfrim();
  }
};
const removeUnusedSource = async (sourceId: string) => {
  // 如果是最后一个引用这个源的图层，则删除源
  const isExist = sceneStore.currentSceneConfig.sources.some(
    (item: any) => item.sourceId === sourceId,
  );
  const isUsedByLayer = isSourceUsedByLayer(
    sourceId,
    sceneStore.currentSceneConfig.layers,
  );
  // 当某个源被聚合源引用时，不删除这个源
  const isUsedByCluster = sceneStore.currentSceneConfig.sources.some(
    (item: any) => item.sourceId === `${sourceId}_cluster`,
  );
  const isUsed = isUsedByLayer || isUsedByCluster;
  if (isExist && !isUsed) {
    const source = sceneStore.currentSceneConfig.sources.find(
      (item: any) => item.sourceId === sourceId,
    );
    await removeSource(source);
  }
  // 聚合源删除时，如果被聚合源引用的源没有图层引用，则删除源
  if (sourceId.endsWith('_cluster')) {
    const oriSourceId = sourceId.split('_cluster')[0] as string;
    const isExist = sceneStore.currentSceneConfig.sources.some(
      (item: any) => item.sourceId === oriSourceId,
    );
    const isOriSourceUsedByLayer = isSourceUsedByLayer(
      oriSourceId,
      sceneStore.currentSceneConfig.layers,
    );
    if (isExist && !isOriSourceUsedByLayer) {
      const source = sceneStore.currentSceneConfig.sources.find(
        (item: any) => item.sourceId === oriSourceId,
      );
      await removeSource(source);
    }
  }
};
const handleRemoveLayer = (layer: any, isInGroupLayer: boolean) => {
  if (layer.organizationType === 'singleLayer') {
    ElMessageBox.confirm(
      // '数据源挂载图层将被移除，其他使用该数据源图层将不可用，是否继续?',
      `确认移除图层：${layer.name}?`,
      '提示',
      {
        confirmButtonText: '继续',
        cancelButtonText: '取消',
        type: 'warning',
      },
    )
      .then(async () => {
        removeSceneLayer(layer);
        // 补充删除底图源
        removeBaseMapSource(layer);
        // 更新store
        if (isInGroupLayer) {
          for (
            let i = 0;
            i < sceneStore.currentSceneConfig.layers.length;
            i++
          ) {
            const element = sceneStore.currentSceneConfig.layers[i] as Layer;
            // 如果元素的 id 匹配，从当前数组中移除该元素
            if (element.id === layer.id) {
              sceneStore.currentSceneConfig.layers.splice(i, 1);
            }
            // 如果元素是 groupLayer 类型，则遍历其 layers 属性
            if (element.organizationType === 'groupLayer') {
              for (let j = 0; j < element.layers.length!; j++) {
                const item = element.layers[j];
                if (item?.id === layer.id) {
                  element.layers.splice(j, 1);
                }
              }
            }
          }
        } else {
          sceneStore.currentSceneConfig.layers =
            sceneStore.currentSceneConfig.layers.filter(
              (layerItem: any) => layerItem.id !== layer.id,
            );
        }
        // 删除未使用的源
        await removeUnusedSource(layer.source);
        ElMessage({
          type: 'success',
          message: '移除成功！',
        });
      })
      .catch(() => {
        ElMessage({
          type: 'info',
          message: '取消移除',
        });
      });
  } else {
    if (layer.layers.length > 0) {
      ElMessageBox.confirm(
        `确认移除图层组：${layer.name}?（将移除图层组内所有图层）`,
        '提示',
        {
          confirmButtonText: '继续',
          cancelButtonText: '取消',
          type: 'warning',
        },
      )
        .then(() => {
          layer.layers.forEach((sublayer: any) => {
            // mapbox.map.removeLayer(sublayer.id)
            removeSceneLayer(sublayer);
            // 补充删除底图源
            removeBaseMapSource(sublayer);
          });
          sceneStore.currentSceneConfig.layers =
            sceneStore.currentSceneConfig.layers.filter(
              (layerItem: any) => layerItem.id !== layer.id,
            );
          ElMessage({
            type: 'success',
            message: '删除成功！',
          });
        })
        .catch(() => {
          ElMessage({
            type: 'info',
            message: '取消删除',
          });
        });
    } else {
      sceneStore.currentSceneConfig.layers =
        sceneStore.currentSceneConfig.layers.filter(
          (layerItem: any) => layerItem.id !== layer.id,
        );
      ElMessage.success('删除成功');
    }
  }
};

const removeAllSources = async () => {
  const tifSourceExist = sceneStore.currentSceneConfig.sources.some(
    (item: any) => item.sourceType === 'image' && item.fileType === 'tif',
  );
  for (let i = sceneStore.currentSceneConfig.sources.length - 1; i >= 0; i--) {
    const source = sceneStore.currentSceneConfig.sources[i];
    mapbox.map.removeSource(source?.sourceId);
    // 摘除副本
    if (source?.sourceType === 'image' && source.fileType === 'tif') {
      await rasterServiceApi.deleteRasterSCopy(
        sceneStore.editingScene.sceneId,
        source.sourceId,
      );
    }
  }
  sceneStore.currentSceneConfig.sources = [];
  // 有tif源的情况下保存
  if (tifSourceExist) {
    await handleSaveConfrim();
  }
};
const handleRemoveAllLayers = () => {
  if (sceneStore.currentSceneConfig.layers.length > 0) {
    ElMessageBox.confirm('确认清除所有图层?', '提示', {
      confirmButtonText: '继续',
      cancelButtonText: '取消',
      type: 'error',
      icon: markRaw(ElQuestionFilled),
    })
      .then(async () => {
        for (
          let i = sceneStore.currentSceneConfig.layers.length - 1;
          i >= 0;
          i--
        ) {
          const layer = sceneStore.currentSceneConfig.layers[i] as Layer;
          if (layer.organizationType === 'singleLayer') {
            // mapbox.map.removeLayer(sceneStore.currentSceneConfig.layers[i].id)
            removeSceneLayer(layer);
            removeBaseMapSource(layer);
            // if (typeof sceneStore.currentSceneConfig.layers[i].source !== 'string') {
            //   mapbox.map.removeSource(sceneStore.currentSceneConfig.layers[i].id)
            // }
          } else {
            const layers = layer.layers;
            for (let j = layers?.length - 1; j >= 0; j--) {
              // mapbox.map.removeLayer(layers[j].id)
              removeSceneLayer(layers?.[j]);
              removeBaseMapSource(layers?.[j]);
            }
          }
        }
        sceneStore.currentSceneConfig.layers = [];
        // 清空源
        await removeAllSources();
        ElMessage({
          type: 'success',
          message: '清除成功！',
        });
      })
      .catch(() => {
        ElMessage({
          type: 'info',
          message: '取消清空',
        });
      });
  } else {
    ElMessage.error('当前场景没有图层');
  }
};

let beforeLayerGroup: any;
const handleDragStart = () => {
  // console.log('拖拽开始');
  // handleDragLayer函数在拖拽结束后才会执行，需要记录一下拖拽前的图层顺序，同时不能直接赋值，否则会因为响应式随着sceneStore.currentSceneConfig.sceneLayerGroup的变化而变化
  beforeLayerGroup = cloneDeep(sceneStore.currentSceneConfig.layers);
};

// 对addLayer方法的封装
const addSceneLayer = (compositeLayer: any, beforeId?: string) => {
  addCompositeLayer(compositeLayer, mapbox.map, beforeId);
};

// 获取指定单图层的上一个图层
const getLastLayer = (layer: any, type?: any) => {
  const layerList =
    type === 'drag'
      ? beforeLayerGroup
      : cloneDeep(sceneStore.currentSceneConfig.layers);
  return getLastLayerOfTree(layer.id, layerList);
};
const handleDragLayer = (moveLayer: any, aimLayer: any, direction: any) => {
  const aimLayerIndex = beforeLayerGroup.findIndex(
    (layer: any) => layer.id === aimLayer.id,
  );
  // console.log('移动前图层', beforeLayerGroup);

  // 移动图层是单图层
  if (moveLayer.organizationType === 'singleLayer') {
    // 目标图层是单图层
    if (aimLayer.organizationType === 'singleLayer') {
      // 移动到目标图层的上面
      if (direction === 'before') {
        // console.log('目标图层', aimLayer);

        const aimLastLayer = getLastLayer(aimLayer, 'drag');
        // console.log('上一个图层', aimLastLayer);
        if (aimLastLayer) {
          if (aimLastLayer.id === moveLayer.id) return;
          removeSceneLayer(moveLayer, 'drag');
          addSceneLayer(moveLayer, aimLastLayer.id);
        } else {
          removeSceneLayer(moveLayer, 'drag');
          addSceneLayer(moveLayer);
        }
      }
      // 移动到目标图层的下面
      else {
        removeSceneLayer(moveLayer, 'drag');
        addSceneLayer(moveLayer, aimLayer.id);
      }
    }
    // 目标图层是图层组
    else {
      // console.log('目标图层', aimLayer);
      // console.log(aimLayer.layers.length);
      // 单图层移到图层组里面
      if (direction === 'inner') {
        // 如果是空图层组
        // 当拖入图层进去时，该图层的length已经增加了1，所以要去掉
        if (aimLayer.layers.length === 1) {
          const layerUpGroupIndex = aimLayerIndex - 1;
          aimLayer = beforeLayerGroup[layerUpGroupIndex];
          // 如果这个图层组上面还有图层
          if (aimLayer) {
            // 如果该图层是单图层
            if (aimLayer.organizationType === 'singleLayer') {
              if (aimLayer.id === moveLayer.id) {
                return;
              }
              removeSceneLayer(moveLayer, 'drag');
              addSceneLayer(moveLayer, aimLayer.id);
            }
            // 因为限制了只能有一个空图层组存在，所以如果该图层是图层组，则一定不是空图层
            else {
              // 则移到该图层组最后一个图层的下方
              aimLayer = aimLayer.layers[aimLayer.layers.length - 1];
              if (aimLayer.id === moveLayer.id) return;
              removeSceneLayer(moveLayer, 'drag');
              addSceneLayer(moveLayer, aimLayer.id);
            }
          }
          // 如果该图层组上面没有图层，则直接添加到地图最上方
          else {
            removeSceneLayer(moveLayer, 'drag');
            addSceneLayer(moveLayer);
          }
        }
        // 如果不是空图层组，则直接移入该图层组的最后一个图层的下方
        else {
          aimLayer = aimLayer.layers[aimLayer.layers.length - 2];
          removeSceneLayer(moveLayer, 'drag');
          addSceneLayer(moveLayer, aimLayer.id);
        }
      }
      // 单图层移到图层组前面
      else if (direction === 'before') {
        // 如果图层组不为空
        if (aimLayer.layers.length > 0) {
          aimLayer = aimLayer.layers[0];
          const aimLastLayer = getLastLayer(aimLayer, 'drag');
          if (aimLastLayer) {
            if (aimLastLayer.id === moveLayer.id) return;
            removeSceneLayer(moveLayer, 'drag');
            addSceneLayer(moveLayer, aimLastLayer.id);
          } else {
            removeSceneLayer(moveLayer, 'drag');
            addSceneLayer(moveLayer);
          }
        }
        // 如果图层组为空
        // 则只需找该图层组下一个图层的上个图层
        else {
          aimLayer = beforeLayerGroup[aimLayerIndex + 1];
          if (aimLayer.organizationType === 'groupLayer') {
            aimLayer = aimLayer.layers[0];
          }
          const aimLastLayer = getLastLayer(aimLayer, 'drag');
          if (aimLastLayer) {
            if (aimLastLayer.id === moveLayer.id) return;
            removeSceneLayer(moveLayer, 'drag');
            addSceneLayer(moveLayer, aimLastLayer.id);
          } else {
            removeSceneLayer(moveLayer, 'drag');
            addSceneLayer(moveLayer);
          }
        }
      }
      // 单图层移到图层组后面
      else {
        // 如果图层组不为空，则移到该图层组中最后一个图层的下面
        if (aimLayer.layers.length > 0) {
          removeSceneLayer(moveLayer, 'drag');
          aimLayer = aimLayer.layers[aimLayer.layers.length - 1];
          addSceneLayer(moveLayer, aimLayer.id);
        }
        // 否则如果图层组为空，则移到该图层组上一个图层的下面
        else {
          // 如果上一个图层存在
          aimLayer = beforeLayerGroup[aimLayerIndex - 1];
          if (aimLayer) {
            // 且是单图层，则移到该图层的下面
            if (aimLayer.organizationType === 'singleLayer') {
              // 特殊情况
              if (aimLayer.id === moveLayer.id) {
                return;
              }
              removeSceneLayer(moveLayer, 'drag');
              addSceneLayer(moveLayer, aimLayer.id);
            }
            // 且是图层组，则该图层组不可能是空图层组，所以直接移到该图层组最后一个图层的下面
            else {
              aimLayer = aimLayer.layers[aimLayer.layers.length - 1];
              if (aimLayer.id === moveLayer.id) return;
              removeSceneLayer(moveLayer, 'drag');
              addSceneLayer(moveLayer, aimLayer.id);
            }
          }
          // 如果上一个图层不存在，直接默认添加到地图最上方
          else {
            removeSceneLayer(moveLayer, 'drag');
            addSceneLayer(moveLayer);
          }
        }
      }
    }
  }
  // 移动目标是图层组
  else {
    // 如果图层不为空
    if (moveLayer.layers.length > 0) {
      // 不能将移除所有图层作为公共部分提取出来，否则顺序会受到影响
      // mapbox.map.layers.forEach((layer: any) => {
      //   mapbox.map.removeLayer(layer.id)
      // })
      // 如果是aimLayer是单图层
      if (aimLayer.organizationType === 'singleLayer') {
        // 移动到该单图层的下面
        if (direction === 'after') {
          for (let i = moveLayer.layers.length - 1; i >= 0; i--) {
            removeSceneLayer(moveLayer.layers[i], 'drag');
            addSceneLayer(
              moveLayer.layers[i],
              beforeLayerGroup[aimLayerIndex].id,
            );
          }
        }
        // 移动到该单图层的上面
        else {
          const aimLastLayer = getLastLayer(aimLayer, 'drag');
          for (let i = moveLayer.layers.length - 1; i >= 0; i--) {
            removeSceneLayer(moveLayer.layers[i], 'drag');
            if (aimLastLayer) {
              addSceneLayer(moveLayer.layers[i], aimLastLayer.id);
            } else {
              addSceneLayer(moveLayer.layers[i]);
            }
          }
        }
      }
      // 如果是aimLayer是图层组
      else {
        // 移动到图层组后面
        if (direction === 'after') {
          // 如果图层组不为空，则移到该图层组中最后一个图层的下面
          if (aimLayer.layers.length > 0) {
            aimLayer = aimLayer.layers[aimLayer.layers.length - 1];
            for (let i = moveLayer.layers.length - 1; i >= 0; i--) {
              removeSceneLayer(moveLayer.layers[i], 'drag');
              addSceneLayer(moveLayer.layers[i], aimLayer.id);
            }
          } else {
            // 否则如果图层组为空
            const layerUpGroup = beforeLayerGroup[aimLayerIndex - 1];
            // 如果上一个图层存在
            if (layerUpGroup) {
              // 且是单图层，则移到该图层下面
              if (layerUpGroup.organizationType === 'singleLayer') {
                for (let i = moveLayer.layers.length - 1; i >= 0; i--) {
                  removeSceneLayer(moveLayer.layers[i], 'drag');
                  addSceneLayer(moveLayer.layers[i], layerUpGroup.id);
                }
              }
              // 且是图层组，则该图层组不可能是空图层组，所以直接移到该图层组最后一个图层的下面
              else {
                if (layerUpGroup.id !== moveLayer.id) {
                  for (let i = moveLayer.layers.length - 1; i >= 0; i--) {
                    removeSceneLayer(moveLayer.layers[i], 'drag');
                    addSceneLayer(
                      moveLayer.layers[i],
                      layerUpGroup[moveLayer.layers.length - 1].id,
                    );
                  }
                }
              }
            }
            // 且图层组上方无图层，直接默认添加到地图最上方
            else {
              for (let i = moveLayer.layers.length - 1; i >= 0; i--) {
                removeSceneLayer(moveLayer.layers[i], 'drag');
                addSceneLayer(moveLayer.layers[i]);
              }
            }
          }
        }
        // 移动到图层组前面
        else {
          // 如果图层组不为空，则移到该图层组中第一个图层的下面
          if (aimLayer.layers.length > 0) {
            const aimLastLayer = getLastLayer(aimLayer.layers[0], 'drag');
            for (let i = moveLayer.layers.length - 1; i >= 0; i--) {
              removeSceneLayer(moveLayer.layers[i], 'drag');
              if (aimLastLayer) {
                addSceneLayer(moveLayer.layers[i], aimLastLayer.id);
              } else {
                addSceneLayer(moveLayer.layers[i]);
              }
            }
          } else {
            // 否则如果图层组为空
            const layerUpGroup = beforeLayerGroup[aimLayerIndex - 1];
            // 如果上一个图层存在
            if (layerUpGroup) {
              // 且是单图层，则移到该图层下面
              if (layerUpGroup.organizationType === 'singleLayer') {
                for (let i = moveLayer.layers.length - 1; i >= 0; i--) {
                  removeSceneLayer(moveLayer.layers[i], 'drag');
                  addSceneLayer(moveLayer.layers[i], layerUpGroup.id);
                }
              }
              // 且是图层组，则该图层组不可能是空图层组，所以直接移到该图层组最后一个图层的下面
              else {
                if (layerUpGroup.id !== moveLayer.id) {
                  for (let i = moveLayer.layers.length - 1; i >= 0; i--) {
                    removeSceneLayer(moveLayer.layers[i], 'drag');
                    addSceneLayer(
                      moveLayer.layers[i],
                      layerUpGroup[moveLayer.layers.length - 1].id,
                    );
                  }
                }
              }
            }
            // 且图层组上方无图层，直接默认添加到地图最上方
            else {
              for (let i = moveLayer.layers.length - 1; i >= 0; i--) {
                removeSceneLayer(moveLayer.layers[i], 'drag');
                addSceneLayer(moveLayer.layers[i]);
              }
            }
          }
        }
      }
    }
  }
};

const handleOpenLayerPropertyDialog = (layer: any) => {
  currentSelectedLayer.value = layer;
  if (
    [
      'img_mapSource_annotate',
      'img_mapSource_map',
      'vec_mapSource_annotate',
      'vec_mapSource_map',
    ].includes(currentSelectedLayer.value.source)
  ) {
    ElMessage.error('底图图层暂不支持查看属性！');
    return;
  }
  isLayerPropertyDialogShow.value = true;
};

const handleAddLayerGroup = () => {
  sceneStore.currentSceneConfig.layers.unshift({
    id: `group_${nanoid()}`, // groupID
    name: 'untitled',
    // 图层组内图层，初始为空
    layers: [],
    organizationType: 'groupLayer',
    isRenaming: false,
  });
  ElMessage.success('图层组添加成功!');
};

const handleCloseAnimation = (groupLayerId: string) => {
  isAnimationControlShow.value = false;
  const groupLayer = sceneStore.currentSceneConfig.layers.find(
    (item: any) => item.id === groupLayerId,
  ) as GroupLayer;
  groupLayer.renderParams!.isAnimationOpen = false;
};
const renderLayer = async (type: string) => {
  // console.log(type);
  if (type === 'timeAnimation') {
    if (!isAnimationControlShow.value) isAnimationControlShow.value = true;
    const {
      layer,
      playOptions: { timeInterval, loop, fitExtent },
      layerDescriptions,
      isAnimationOpen,
    } = publicStore.RenderOptions;
    layer.renderType = 'timeAnimation';
    layer.renderParams = {
      isAnimationOpen,
      timeInterval,
      loop,
      fitExtent,
      layerDescriptions,
    };
    animationParams.value = {
      title: layer.name,
      groupLayerId: layer.id,
      timeInterval,
      loop,
      fitExtent,
      layerList: layerDescriptions,
    };
    return;
  }
  await renderEntry(type, currentSelectedLayer);
  // renderEntry必须写成异步，等渲染完成后参数才保存到store,这时候保存场景才有效
  if (type === 'singleBandRasterRender') {
    await handleSaveConfrim(300);
  }
};
const changeSpriteLib = (sprite: string) => {
  // console.log(sprite);
  const style = mapbox.map.getStyle();
  style.sprite = `${mapboxAssetsIP}/sprites/${sprite}/sprite`;

  mapbox.map.setStyle(style);
};

const handleAutoRenderLayer = async (layer: any) => {
  currentSelectedLayer.value = layer;
  // const templateParams = {
  //   colorRamp: 'random',
  //   renderField: 'rate',
  //   renderParam: {
  //     layout: {
  //       'visibility': 'visible'
  //     },
  //     paint: {
  //       "fill-opacity": 100,
  //       "fill-outline-color": "#000000",
  //     }
  //   }
  // }
  const templateParams = {
    renderField: 'name',
    renderParam: {
      layout: {
        visibility: 'visible',
        'text-font': ['Open Sans Semibold'],
        'text-size': 12,
        'text-allow-overlap': false,
        'text-ignore-placement': false,
        'text-anchor': 'center',
        'text-justify': 'center',
        'text-offset': [0, 0],
        'text-rotate': 0,
        'text-transform': 'none',
        'text-writing-mode': ['horizontal'],
        'symbol-placement': 'point',
      },
      paint: {
        'text-color': '#000000',
        'text-halo-color': '#ccefc2',
        'text-halo-blur': 0,
        'text-halo-width': 1,
        'text-opacity': 100,
      },
    },
  };
  // console.log(currentSelectedLayer.value);

  // const renderParams = await getHierarchicalRenderParams(templateParams, currentSelectedLayer)
  // const renderParams = await getHeatmapParams(templateParams, currentSelectedLayer)
  // const renderParams = await getSingleBandRenderParams(templateParams, currentSelectedLayer)
  const renderParams = await getTextLabelParams(
    templateParams,
    currentSelectedLayer,
  );
  // console.log(renderParams);

  // publicStore.setRenderOptions(renderParams)
  publicStore.setLabelOptions(renderParams);
  // renderLayer("hierarchicalRender")
  // renderLayer("heatMap")
  // renderLayer("singleBandRasterRender")
  renderLayer('textLabel');
};

const availableYears: number[] = [
  // BC3200 到 BC2000，每隔 50 年
  ...Array.from({ length: (3200 - 2000) / 50 + 1 }, (_, i) => -3200 + i * 50),

  // BC2000 到 BC1000，每隔 10 年
  ...Array.from({ length: (2000 - 1000) / 10 + 1 }, (_, i) => -2000 + i * 10),

  // BC1000 到 AD1900，每隔 1 年
  ...Array.from({ length: 1900 + 1000 + 1 }, (_, i) => i - 1000),
];

const formatYearLabel = (year: number): string => {
  return year < 0 ? `BC${-year}` : `AD${year}`;
};

const parseYearString = (yearStr: string): number => {
  if (yearStr.startsWith('BC')) return -Number(yearStr.slice(2));
  if (yearStr.startsWith('AD')) return Number(yearStr.slice(2));
  return Number(yearStr); // fallback
};

const findNearestAvailableYear = (targetYear: number): number => {
  if (targetYear === 0) return 1;
  if (availableYears.includes(targetYear)) return targetYear;

  let nearest = availableYears[0] || 750;
  let minDiff = Math.abs(nearest - targetYear);

  for (const year of availableYears) {
    const diff = Math.abs(year - targetYear);
    if (diff < minDiff) {
      nearest = year;
      minDiff = diff;
    }
  }

  return nearest;
};

const getHistoryStyleWithLayers = (style: any) => {
  // 先去除之前的历史图层
  const sourcesNoHistory = mapbox.map.getStyle().sources;
  delete sourcesNoHistory.dlsgis_his_regime;
  const layersNoHistory = mapbox.map
    .getStyle()
    .layers.filter((layer: any) => layer.source !== 'dlsgis_his_regime');
  // 提取出底图和自定义图层
  const baseMapIds = new Set(
    Object.values(baseMapLayers).flatMap((layer) =>
      layer.map((item) => item.id),
    ),
  );
  const baseMaps = layersNoHistory.filter((layer: any) =>
    baseMapIds.has(layer.id),
  );
  const customLayers = layersNoHistory.filter(
    (layer: any) => !baseMapIds.has(layer.id),
  );

  // 底图放到最底下
  if (baseMaps.length > 0) {
    style.layers = [...baseMaps, ...style.layers];
  }

  style.sources = { ...style.sources, ...sourcesNoHistory };
  // 自定义图层按照顺序放到最上面
  style.layers = [...style.layers, ...customLayers];
  return style;
};
const fetchHistoryLayerStyle = async (year: string) => {
  const parsedYear = parseYearString(year); // 转为数字
  const nearestYear = findNearestAvailableYear(parsedYear); // 找最近的
  const nearestYearStr = formatYearLabel(nearestYear); // 转回 BC/AD 形式

  // 如果找到了不同的年份，提示用户
  if (nearestYear !== parsedYear) {
    ElMessage.warning(
      `暂无 ${year} 年的数据，已切换至最近的 ${nearestYearStr} 年的疆域数据`,
    );
  }

  // 用最近可用的 BC/AD 年份发请求
  const response = await fetch(historyApi.getHistoryMapStyle(nearestYearStr));
  if (!response.ok) throw new Error('样式加载失败');

  let style = await response.json();
  style.sources.dlsgis_his_regime.tiles = [
    historyApi.getHistoryTilesURL(nearestYearStr),
  ];
  style.glyphs = `${mapboxAssetsIP}/glyphs/fonts/{fontstack}/{range}.pbf`;
  style.sprite = `${mapboxAssetsIP}/sprites/${sceneStore.currentSceneConfig.sprite}/sprite`;
  style = getHistoryStyleWithLayers(style);
  return style;
};

const showHistoryMap = async () => {
  if (isHistoryMode.value) {
    isHistoryMode.value = false;
    showJump2Era.value = false;
    showTimeRuler.value = false;
    // update store
    sceneStore.currentSceneConfig.mapParams.historyMap = 0;
  } else {
    isHistoryMode.value = true;
    showJump2Era.value = true;
    showTimeRuler.value = false;
  }
};

const selectedRange = ref<[number, number]>([700, 750]);
const dropdownYear = ref(750);

const handleUpdateTimeRange = async (timeRange: [number, number]) => {
  selectedRange.value = timeRange;
  isHistoryMode.value = true; // ✅ 保持一致逻辑

  const endLayer = timeRange[1] || 0;
  const formattedYear = endLayer < 0 ? `BC${-endLayer}` : `AD${endLayer}`;
  dropdownYear.value = endLayer;
  const style = await fetchHistoryLayerStyle(formattedYear);

  mapbox.map.setStyle(style);
  if (mapMode.value === 'globe') {
    mapbox.map.on('style.load', () => {
      mapbox.map.setFog({});
    });
  }
  showTimeRuler.value = true;

  // update store
  if (isHistoryMode.value) {
    sceneStore.currentSceneConfig.mapParams.historyMap = timeRange[1];
  }
  // mapbox.map.once('idle', async () => {
  //   await handleSwitchMap({
  //     id: 'ter_map',
  //     type: 'terrain',
  //     label: '地形',
  //   });
  mapbox.map.setZoom(3);
  // });
};
const initHistoryMap = () => {
  const year = sceneStore.currentSceneConfig.mapParams.historyMap;
  if (year) {
    handleUpdateTimeRange([year - 50, year]);
  }
};
const onYearDropdownChange = (year: number) => {
  handleUpdateTimeRange([year - 50, year]);
};

onMounted(async () => {
  // 先从session中获取editScene，赋值给store
  // const editingScene = JSON.parse(storageManager.getItem('editingScene') as any)
  const editingScene = storageManager.getItem('editingScene') as Scene;
  // console.log('session中的', editingScene)
  sceneStore.setEditingScene(editingScene);

  const sceneLoading = ElLoading.service({
    lock: true,
    text: loadingText.value,
    background: 'rgba(0, 0, 0, 0.7)',
  });
  sceneLoading.setText('初始化地图中，请稍后...');
  sceneLoading.setText((await initMap()) as string);
  sceneLoading.setText((await requestMapConfig()) as string);
  initRender(mapbox.map);

  initMapMode();
  initHistoryMap();
  // 如果当前场景没有Id，则表明该场景尚未创建，则不去请求添加数据源和渲染图层
  if (sceneStore.editingScene.sceneId !== '') {
    sceneLoading.setText((await loadSourcesToMap()) as string);
    sceneLoading.setText((await renderSceneLayersInMap()) as string);
  }
  if (sceneStore.editingScene.sceneId === '') {
    ElMessage({
      type: 'success',
      message: '地理数据可视化临时场景建立成功!',
    });
  } else {
    ElMessage({
      type: 'success',
      message: `场景 ${sceneStore.editingScene.sceneName} 加载成功!`,
    });
  }
  sceneLoading.close();
  watch(
    () => sceneStore.currentSceneConfig.sprite,
    (newVal: string) => {
      changeSpriteLib(newVal);
    },
  );
  watch(
    () => sceneStore.currentSceneConfig.layers,
    () => {
      sceneLayersGroup.value = sceneStore.currentSceneConfig.layers;
    },
    {
      deep: true,
    },
  );
  watch(
    () => activatedMenu.value,
    () => {
      nextTick(() => {
        mapbox.map.resize();
      });
    },
  );
  // 类似的监听并更新数据源列表，以便及时反馈给数据源组件实时显示
  watch(
    () => sceneStore.currentSceneConfig.sources,
    () => {
      // console.log('数据源列表变化了')
      sceneSourcesGroup.value = sceneStore.currentSceneConfig.sources;
    },
    {
      deep: true,
    },
  );
  // 初始化图层组（数据）、初始化工具库、easeTo飞向数据
  // 可以在scene中加入isEditing属性,判断是否在编辑状态
});
onBeforeRouteLeave((_to, _from, next) => {
  // 判断目标路由是否是预览页
  const isPreviewRoute = _to.path.startsWith('/map-preview/');

  if (sceneStore.editingScene.isLocked || isPreviewRoute) {
    next();
  } else {
    ElMessageBox.confirm('是否保存当前场景并退出？', '退出', {
      distinguishCancelAndClose: true,
      confirmButtonText: '保存并退出',
      cancelButtonText: '直接退出',
      type: 'warning',
    })
      .then(async () => {
        await handleSaveConfrim();
        next();
        // Session.remove("editingScene");
      })
      .catch((error: Action) => {
        if (error === 'cancel') {
          next();
          // Session.remove("editingScene");
        }
        if (error === 'close') {
          next(false);
        }
      });
  }
});
</script>

<template>
  <div class="allcontainer">
    <div class="header">
      <div class="left-btn">
        <ElIcon size="22" color="#ccc" @click="backScene">
          <SystemUiconsWrapBack />
        </ElIcon>
      </div>
      <div class="title">
        <ElIcon size="22">
          <SvgMapIcon />
        </ElIcon>
        <span>{{ sceneStore.editingScene.sceneName }}</span>
      </div>
      <div class="right-btn">
        <ElSpace :size="22">
          <ElTooltip placement="bottom" content="关闭历史地图">
            <ElIcon
              size="21"
              color="#ccc"
              v-if="isHistoryMode"
              @click="handletoggleCloseHistoryMap"
            >
              <ElClose />
            </ElIcon>
          </ElTooltip>
          <ElTooltip placement="bottom" content="全屏">
            <ElIcon size="21" color="#ccc" @click="handletoggleFullScreen">
              <ElFullScreen />
            </ElIcon>
          </ElTooltip>
          <ElTooltip placement="bottom" content="帮助">
            <ElIcon size="21" color="#ccc">
              <SimpleLineIconsQuestion />
            </ElIcon>
          </ElTooltip>
        </ElSpace>
      </div>
    </div>
    <div class="body">
      <div class="menuCon">
        <ElMenu
          :default-active="activatedMenu"
          class="el-menu-vertical-demo"
          :collapse="isCollapse"
          @select="handleSelect"
          :collapse-transition="false"
          text-color="#BABABA"
          active-text-color="#fff"
          background-color="#2b2b2b"
        >
          <div class="menuTop">
            <ElMenuItem index="1">
              <ElIcon>
                <ElCirclePlus />
              </ElIcon>
              <template #title>添加</template>
            </ElMenuItem>
            <ElMenuItem index="2">
              <ElIcon size="20">
                <BxsLayer />
              </ElIcon>
              <template #title>图层</template>
            </ElMenuItem>
            <ElTooltip content="历史底图" placement="right">
              <div class="menu-btn" @click="showHistoryMap()">
                <div style="display: flex; align-items: center">
                  <ElIcon size="18" style="position: absolute; left: 19px">
                    <ElMapLocation />
                  </ElIcon>
                </div>
              </div>
            </ElTooltip>
          </div>
          <div class="menuBottom">
            <ElMenuItem index="4" @click="handleExport">
              <ElIcon size="20">
                <BxExport />
              </ElIcon>
              <template #title>导出</template>
            </ElMenuItem>
            <ElMenuItem
              index="5"
              @click="handleSaveConfrim()"
              :disabled="sceneStore.editingScene.isLocked"
            >
              <ElIcon size="20">
                <MingcuteSave2Line />
              </ElIcon>
              <template #title>保存</template>
            </ElMenuItem>
            <ElMenuItem index="6">
              <ElIcon>
                <ElTools />
              </ElIcon>
              <template #title>设置</template>
            </ElMenuItem>
          </div>
        </ElMenu>
        <ElDivider
          border-style="hidden"
          style="margin-top: 0; margin-bottom: 0; background-color: #787878"
        />
        <ElTooltip content="展开" placement="right" v-if="isCollapse">
          <div class="menu-btn" @click="isCollapse = !isCollapse">
            <!-- <el-button size="large" type="text" :icon="isCollapse ? Expand : Fold" @click="isCollapse = !isCollapse"><span
            v-if="!isCollapse">收起</span></el-button> -->
            <div style="display: flex; align-items: center">
              <ElIcon size="18" style="position: absolute; left: 19px">
                <ElDArrowRight />
              </ElIcon>
            </div>
          </div>
        </ElTooltip>
        <div class="menu-btn" @click="isCollapse = !isCollapse" v-else>
          <div style="display: flex; align-items: center">
            <ElIcon size="18" style="position: absolute; left: 19px">
              <ElDArrowLeft />
            </ElIcon>
            &nbsp;&nbsp;&nbsp;&nbsp;
            <span style="font-size: 14px">折叠</span>
          </div>
        </div>
      </div>

      <div class="editContainer" v-if="activatedMenu === '2'">
        <div id="layerPannel" class="layerPannel">
          <LayerPanel
            ref="layerPannelRef"
            :menu-width="isCollapse ? '65px' : '113px'"
            @close-layer-pannel="handleCloseLayerPannel"
            :layer-list="sceneLayersGroup"
            :is-locked="sceneStore.editingScene.isLocked"
            @set-layer-visibility="handleSetLayerVisibility"
            @remove-layer="handleRemoveLayer"
            @drag-layer="handleDragLayer"
            @drag-start="handleDragStart"
            @zoom-to-layer="handleZoomToLayer"
            @remove-all-layers="handleRemoveAllLayers"
            @add-layer-group="handleAddLayerGroup"
            @add-to-layer="handleAddToLayer"
            @open-layer-property-dialog="handleOpenLayerPropertyDialog"
            @auto-render-layer="handleAutoRenderLayer"
          />
        </div>
      </div>

      <div class="settingPannel" v-if="activatedMenu === '6'">
        <GDVSceneSettingPanel
          @close-setting-pannel="activatedMenu = '0'"
          :is-scene-renameing="isSceneRenaming"
        />
      </div>
      <div class="map-box">
        <div id="map-container" ref="mapContainer">
          <ElTag class="mapZoomLngLat" type="info">
            Zoom:{{ zoomText }} &nbsp; LngLat:{{ showCenter }}
          </ElTag>

          <div class="export-control">
            <ElIcon
              class="control-btn"
              size="27"
              title="导出地图上的绘制"
              @click="exportGeojson"
            >
              <ElFolderChecked />
            </ElIcon>
          </div>
          <div class="homemap-control">
            <ElIcon
              class="control-btn"
              size="27"
              title="回到初始状态"
              @click="initMapState(0)"
            >
              <ElHomeFilled />
            </ElIcon>
          </div>
          <div class="mapmode-control">
            <ElPopover
              placement="left-end"
              :width="80"
              trigger="click"
              :teleported="false"
              transition="none"
              :hide-after="0"
              :popper-style="{ minWidth: '80px', padding: '5px' }"
            >
              <template #default>
                <div class="mapmode-sub-control">
                  <ElIcon
                    size="27"
                    class="sub-control-btn"
                    title="平面"
                    :class="{
                      'mode-active': mapMode === mapModeList[0]?.value,
                    }"
                    @click="toggleMapMode(mapModeList[0])"
                  >
                    <PixelarticonsGrid />
                  </ElIcon>
                  <ElDivider
                    direction="vertical"
                    border-style="hidden"
                    style="margin-right: 3px; margin-left: 3px"
                  />
                  <ElIcon
                    size="24"
                    class="sub-control-btn"
                    title="3D"
                    :class="{
                      'mode-active': mapMode === mapModeList[1]?.value,
                    }"
                    @click="toggleMapMode(mapModeList[1])"
                  >
                    <BiGlobe />
                  </ElIcon>
                </div>
              </template>
              <template #reference>
                <ElIcon
                  v-if="mapMode === 'mercator'"
                  size="27"
                  class="control-btn"
                  title="平面"
                >
                  <PixelarticonsGrid />
                </ElIcon>
                <ElIcon v-else size="25" class="control-btn" title="3D">
                  <BiGlobe />
                </ElIcon>
              </template>
            </ElPopover>
          </div>
          <div class="basemap-control">
            <ElPopover
              placement="left"
              :width="220"
              trigger="click"
              :teleported="false"
              transition="none"
              :hide-after="0"
              :popper-style="{ padding: '2px' }"
            >
              <template #default>
                <BaseMapControl @switch-map="handleSwitchMap" />
              </template>
              <template #reference>
                <ElIcon size="28" class="control-btn" title="底图">
                  <BxLayer />
                </ElIcon>
              </template>
            </ElPopover>
          </div>
          <div class="animation-control">
            <AnimationControl
              v-if="isAnimationControlShow"
              :is-control-show="isAnimationControlShow"
              :title="animationParams.title"
              :group-layer-id="animationParams.groupLayerId"
              :time-interval="animationParams.timeInterval"
              :loop="animationParams.loop"
              :fit-extent="animationParams.fitExtent"
              :layer-list="animationParams.layerList"
              @close-animation="handleCloseAnimation"
              @change-frame="changeFrame"
            />
          </div>
        </div>
        <div class="time-ruler h-20" v-if="showTimeRuler">
          <TimeRulerControl
            :selected-range="selectedRange"
            @update:selected-range="handleUpdateTimeRange"
          />
        </div>
        <div v-if="showJump2Era">
          <Jump2EraControl
            v-model="showJump2Era"
            @update:selected-range="handleUpdateTimeRange"
            :is-jump-2-era-show="showJump2Era"
            @close-jump2era-show-dialog="showJump2Era = false"
          />
        </div>
        <div v-if="showTimeRuler">
          <YearSelection
            v-model="dropdownYear"
            @change="onYearDropdownChange"
            :selected-range="selectedRange"
          />
        </div>
      </div>
    </div>
  </div>
  <!-- <div class="btn" @click="openAIChat">
    <div class="aiAssitant">
      <img class="aiImage" width="50" height="40" src="/robot.png" />
    </div>
    <div>
      <p class="dianwo">点我提问</p>
    </div>
  </div> -->
  <div class="save-scene-dialog">
    <ElDialog
      draggable
      class="dialog-title"
      v-model="saveSceneDialog"
      width="20%"
      align-center
      destroy-on-close
    >
      <template #header>
        <div class="my-header">
          <h4 style="color: rgb(48 45 45)">保存场景</h4>
        </div>
        <ElDivider style="padding: 0; margin: 0" />
      </template>
      <ElDivider
        border-style="hidden"
        style="margin-top: 20px; margin-bottom: 0"
      />
      <ElRow type="flex" align="middle">
        <div class="row-style">
          <ElCol :span="5">
            <span>场景类型：</span>
          </ElCol>
          <ElCol :span="19">
            <ElInput
              :disabled="true"
              size="default"
              placeholder="地理数据可视化场景"
            />
          </ElCol>
        </div>
      </ElRow>
      <ElRow type="flex" align="middle">
        <div class="row-style">
          <ElCol :span="5">
            <span>场景名称：</span>
          </ElCol>
          <ElCol :span="19">
            <ElInput
              v-model.trim="sceneStore.editingScene.sceneName"
              :readonly="isReadonly"
              size="default"
              @blur="isReadonly = true"
            >
              <template #append>
                <ElButton
                  type="primary"
                  size="default"
                  text
                  @click="isReadonly = false"
                  title="单击以更改"
                >
                  更改
                </ElButton>
              </template>
            </ElInput>
          </ElCol>
        </div>
      </ElRow>
      <ElDivider
        border-style="hidden"
        style="margin-top: 0; margin-bottom: 20px"
      />
      <template #footer>
        <span class="dialog-footer">
          <ElButton class="mybtn" type="primary" @click="handleSaveConfrim()">
            确定
          </ElButton>
          <ElButton class="mybtn" @click="saveSceneDialog = false">
            取消
          </ElButton>
        </span>
      </template>
    </ElDialog>
  </div>

  <div class="publish-map-dialog">
    <ElDialog
      v-model="isExportDialogVisible"
      title="导出地图配置"
      :close-on-click-modal="false"
      :width="800"
    >
      <ElForm
        ref="exportFormRef"
        :model="exportForm"
        :rules="exportRules"
        label-width="80px"
      >
        <ElFormItem label="地图名称" prop="mapName" label-width="0">
          <ElRow type="flex" align="middle">
            <div class="row-style">
              <ElCol :span="3">
                <span>地图名称：</span>
              </ElCol>
              <ElCol :span="20">
                <ElInput
                  v-model="exportForm.mapName"
                  placeholder="请输入地图名称"
                  maxlength="50"
                  class="form-input"
                />
              </ElCol>
            </div>
          </ElRow>
        </ElFormItem>
        <ElFormItem label="地图介绍" prop="introduction">
          <ElRow type="flex" align="middle">
            <div class="row-style">
              <ElCol :span="3">
                <span>地图介绍：</span>
              </ElCol>
              <ElCol :span="20">
                <ElInput
                  v-model="exportForm.introduction"
                  type="textarea"
                  placeholder="请输入地图介绍（可选）"
                  :rows="3"
                  maxlength="200"
                />
              </ElCol>
            </div>
          </ElRow>
        </ElFormItem>
      </ElForm>
      <template #footer>
        <ElButton @click="isExportDialogVisible = false">取消</ElButton>
        <ElButton type="primary" @click="confirmExport">确认</ElButton>
      </template>
    </ElDialog>
  </div>

  <LayerProperty
    v-if="isLayerPropertyDialogShow"
    :is-layer-property-dialog-show="isLayerPropertyDialogShow"
    :selected-layer="currentSelectedLayer"
    @close-layer-property-dialog="isLayerPropertyDialogShow = false"
    @send-render-type="renderLayer"
  />
</template>

<style scoped lang="scss">
@keyframes fade-in-right {
  from {
    right: 8vw;
    opacity: 0;
  }

  to {
    right: 9vw;
    opacity: 1;
  }
}

.menuCon {
  display: flex;
  flex-direction: column;
  height: 100%;
  border-right: 1px solid rgb(168 166 166);
}

.editContainer,
.settingPannel {
  box-sizing: border-box;
  flex-shrink: 0;
  width: 100%;
  width: 340px;
  height: 100%;
  // overflow: hidden;
  border-right: 1px solid rgb(202 202 202);
}

/* .resourceManagement {
  width: 100%;
  height: 100%;
} */

/* .dataSourcePannel {
  width: 100%;
  height: 0%;
} */

.dataSourcePannel2 {
  width: 100%;
  height: 100%;

  /* flex: 1; */
}

.layerPannel {
  width: 100%;
  height: 100%;

  /* flex: 1; */
}

.map-box {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  // padding: 5px 0 0 0;
  // background-color: #e4e4e4;
  background-color: #f2f3f7;
  border-top: 1px solid #fff;
}

#map-container {
  position: relative;
  z-index: 10;
  flex: 1;
  width: 100%;
  // height: 100%;
}

.allcontainer {
  display: flex;
  flex-direction: column;
  width: 100vw;
  height: 100vh;
  overflow: hidden;

  /* 禁用滚动 */
}

.header {
  z-index: 11;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  height: 50px;
  // background-color: #fff;
  background-color: #2e3138;
  border-bottom: rgb(175 175 175 / 50%) 1px solid;
  box-shadow: -10px 10px 4px -12px rgb(0 0 0 / 50%);

  /* inset 表示内阴影 */

  .common-btn {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 80%;
  }

  .left-btn {
    /* stylelint-disable-next-line at-rule-no-unknown */
    @extend .common-btn;

    width: 56px;
    border-right: #ccc 1px solid;
  }

  .right-btn {
    /* stylelint-disable-next-line at-rule-no-unknown */
    @extend .common-btn;

    padding-right: 22px;
    // width: 120px;
  }

  .common-btn .el-icon:hover {
    color: #fff;
    cursor: pointer;
  }

  .title {
    display: flex;
    align-items: center;
    font-size: 1.2rem;
    font-weight: 600;
    // color: #333;
    color: #ccc;
    letter-spacing: 1px;

    span {
      // width: 100px;
      height: 30px;
      margin-left: 5px;
      line-height: 30px;
    }
  }
}

.body {
  display: flex;
  flex: 1;
  width: 100%;
}

.menuItemsCon {
  height: 100%;
}

.menu-btn {
  /* 导航栏实际高度比header高，遮住了 */
  z-index: 10;
  display: flex;

  /* text-align: center; */
  align-items: center;
  justify-content: center;
  height: 57px;
  color: #bababa;
  cursor: pointer;
  user-select: none;
  background-color: #2b2b2b;

  &:hover {
    color: #fff;
    background-color: #151515;
  }
}

.icon {
  width: 1em;
  height: 1em;
  overflow: hidden;
  vertical-align: -0.15em;
  fill: currentcolor;
}

.el-menu {
  --el-menu-base-level-padding: 16px;

  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 100%;
  user-select: none;
  border: none;

  // .el-menu-item {
  //   padding: 0 calc(var(--el-menu-base-level-padding) + 8px) 0
  //     var(--el-menu-base-level-padding);
  // }
}

.el-menu-item.is-active {
  width: 100%;
  font-weight: bold;
  background-color: #151515 !important;
}

.el-menu-item:hover {
  /* width: 100%; */
  color: #fff;
  background-color: #151515;
}

.el-menu-item.is-active::before {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-block;
  width: 3px;
  height: 100%;
  content: '';
  background-color: #2f89fc;
}

/* 隐藏logo */
:deep(.mapboxgl-ctrl-logo) {
  display: none !important;
}

:deep(.mapboxgl-ctrl-bottom-right) {
  display: none !important;
}

.mapZoomLngLat {
  position: absolute;
  right: 60px;
  bottom: 10px;
  z-index: 10;
  font-size: 13px;
  background-color: #fff !important;
}

.mapStyleBtn {
  position: absolute;
  top: 40px;
  right: 60px;
  z-index: 10;
  font-size: 13px;
  background-color: #fff !important;
}

.mapmode-control {
  position: absolute;
  right: 20px;
  bottom: 70px;
  z-index: 10;

  .mapmode-sub-control {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 70px;
    height: 30px;

    .sub-control-btn {
      width: 30px;
      height: 100%;
      padding: 2px;
      border: #e7e7e7 solid 2px;
      border-radius: 5px;

      &:not(.mode-active):hover {
        color: #2f89fc;
        cursor: pointer;
        border: #2f89fc solid 2px;
      }
    }

    .mode-active {
      color: #2f89fc;
      border: #2f89fc solid 2px;
    }
  }
}

.basemap-control {
  position: absolute;
  right: 20px;
  bottom: 20px;
  z-index: 10;
}

.homemap-control {
  position: absolute;
  right: 20px;
  bottom: 120px;
  z-index: 10;
}

.export-control {
  position: absolute;
  right: 20px;
  bottom: 170px;
  z-index: 10;
}

.export-control,
.mapmode-control,
.basemap-control,
.homemap-control {
  .control-btn {
    width: 40px;
    height: 40px;
    color: #4d4d4d;
    background-color: rgb(255 255 255 / 50%);
    border: 1px solid rgb(175 175 175 / 50%);
    border-radius: 50%;
    box-shadow:
      0 4px 6px rgb(0 0 0 / 10%),
      0 1px 3px rgb(0 0 0 / 8%);

    /* 初始阴影效果 */
    transition: all 0.3s ease;

    &:hover {
      color: #2f89fc;
      cursor: pointer;
      background-color: rgb(255 255 255 / 80%);
      box-shadow:
        0 15px 30px rgb(0 0 0 / 20%),
        0 10px 15px rgb(0 0 0 / 10%);

      /* 悬浮时的更大阴影 */
      transform: translateY(-6px);

      /* 上浮效果 */
    }
  }
}

.animation-control {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 10;
}

/* 保存对话框 */
.my-header {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  height: 40px;
  padding-top: 10px;
  padding-bottom: 5px;
  padding-left: 20px;
  font-size: 18px;
}

:deep(.save-scene-dialog .el-dialog) {
  height: auto;
  border-radius: 20px;
  box-shadow: 0 0 50px rgb(0 0 0 / 50%);
}

.row-style {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 10px 20px;
}

.mybtn {
  width: 80px;
  height: 30px;
  font-weight: bolder;
  letter-spacing: 1px;
  border-radius: 3px;
}

/* 大模型css */
.btn {
  position: absolute;
  right: 2vw;
  bottom: 4vh;
  z-index: 999;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  width: 120px;
  height: 45px;
  font-family: Dosis, sans-serif;
  font-size: 24px;
  color: white;
  cursor: pointer;
  background-image: linear-gradient(135deg, #fff 0%, #fff 100%);
  border: none;
  border-radius: 30px;
  outline: none;
  box-shadow: 0 20px 30px -6px rgb(255 255 255 / 50%);
  transition: all 0.3s ease-in-out;
}

.btn:active {
  opacity: 0.5;
}

/* robot */
.aiAssitant {
  bottom: 2vh;
  z-index: 999;
  display: flex;
  justify-content: center;
}

.aiImage {
  display: flex;
  align-items: center;
  justify-content: center;
}

.aiImage:hover {
  scale: 1.1;
}

.dianwo {
  font-size: small;
  color: #000;
}

.dianwo:hover {
  color: #5ca7f3;
  cursor: pointer;
}

.aiChatPannel {
  position: absolute;
  right: 9vw;
  bottom: 4vh;
  z-index: 1999;
  width: 25vw;
  height: 66vh;
  padding: 5px;
  background-color: rgb(226 232 240);
  border-radius: 15px;
  box-shadow: -10px 12px 8px -12px #000;
  animation: fade-in-right 0.5s forwards;
}

.draw-result-marker {
  padding: 4px 8px;
  font-size: 12px;
  white-space: nowrap;
  background: white;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-shadow: 0 1px 3px rgb(0 0 0 / 30%);
}
</style>
